import logging
import os
import os.path
import time
import re
import stat
import string

#use the mime type model 
import mimetypes
mimetypes.init()

log = logging.getLogger(__name__)

from pylons import config #get the parameters from the development.ini config
from serverengine.lib import storageHelper

def getFilesList(location, fullPath=True):
    """
    Returns a string list of the files and directories found at 'location'

    location:Location must be a string containing the full path to the directory

    fullPath:Set to True to return the full path of the files/directories default value is True
    """
    dirList = []
    try:
        dirList = os.listdir(location)
    except:
        log.debug("Cannot list the directory")
        fullPath = False
    filteredList = []
    for item in dirList:
        if re.search("^\.", item):
            continue
        if fullPath:
            filteredList.append(os.path.join(location, item))
        else:
            filteredList.append(item)
    return filteredList

def getMimeType(filePath):
    """
    Returns a String showing the mimeType of the file, if mime type not found will return 'unknown'
    
    filePath: could contain the full filepath or only the file name
    """
    #cut the final character if char is ~ 
    if filePath[len(filePath)-1]=='~':
        filePath=filePath[0:len(filePath)-1]
    #guess the mime type
    mime=mimetypes.guess_type(filePath) #returns a turple of the mime type (type,encoding)
    if mime[0]:
        return mime[0]
    else:
        return 'unknown'
    

def getFileSize(filePath):
    """
    Returns a Float containing the size of the file indicated at filePath in bytes.
    
    filePath: must be a string containing the fullpath of the file
    """
    return os.path.getsize(filePath)

def getLastMod(filePath):
    """
    Returns a string containing the Last-modified time of the file. Format is Year-Month-Date Hours:Minutes:Seconds

    filePath: must be a string containing the fullpath of the file
    """
    return time.strftime("%Y-%m-%d %I:%M:%S",time.localtime(os.path.getmtime(filePath)) )

def getFirstCreate(filePath):
    """
    Returns a string containing the Time the file was first created. On Unix systems returns a string containing
    the Last-modified time of the file. Format is Year-Month-Date Hours:Minutes:Seconds
    
    filePath: must be a string containing the fullpath of the file
    """
    return time.strftime("%Y-%m-%d %I:%M:%S",time.localtime(os.path.getctime(filePath)) )   

def getMode(filePath,type="user"):
    """
    Function returns the permission of the file or directory. The value of the permission uses 'r' for readable,
    'w' for writable. The function returns a string containing the three permission flags alike the output found in the 'ls'
    command.

    filePath: must be a string containing the fullpath of the file

    type: set which group to show 'type' can be set to "user","group" or "owner". Default set to 'user'. 
    """
    status = os.stat(filePath)
    mode = status[stat.ST_MODE] 
    mode = str(oct(mode & 0777))[1:] #convert to a string format of the permission 
    if string.lower(type)=="user":
        modNum=mode[0]      
    elif string.lower(type)=="group":
        modNum=mode[1]
    elif string.lower(type)=="owner":
        modNum=mode[2]
    else:
        return "type mismatch"

    if modNum=='7':
        return "rw"
    elif modNum=='6':
        return "rw"
    elif modNum=='5':
        return "r"
    elif modNum=='4':
        return "r"
    elif modNum=='3':
        return "w"
    elif modNum=='2':
        return "w"
    elif modNum=='1':
        return ""
    else:
        return ""


def getUserPath(id = None):
    """
    Function returns a string of the path used to store files and folders for the 'users'.
    The path is the value of the parameter 'userpath' found in the pylons configuration file
    """
    
    sysFile = config['userpath']
    
    # parse for windows if there are backslashes
    if sysFile.find('\\')!=-1:
        sysFile = sysFile.replace('\\','/')
    
    # add final slash if there is none
    if sysFile[-1] != '/':
        sysFile += '/'
    
    # if ID is specified
    if id is not None:
        sysFile += id
    else:
        sysFile = sysFile.replace('/$','')
    return sysFile

def getDirSize(directoryPath):
    """
    Function returns the directory size in bytes by recusively counting the
    files and directory contained in the directory indicated by 'directoryPath'

    directoryPath: must be a string containing the full path to the directory
    """
    directorySize = 0
    for (path, dirs, files) in os.walk(directoryPath):
            for file in files:
                     fileName = os.path.join(path, file)
                     directorySize += os.path.getsize(fileName)
    return directorySize

def locationParser(location, removeLeadingForeslash = True):
    """
    Function returns a string contaning a path to a file or directory which has
    removed / ./ or ../

    location: must be a string containing a path to a file or directory
    """
    if removeLeadingForeslash:
        location = re.sub("^/", "", location)
    location = re.sub("\./", "", location)
    location = re.sub("\.\./", "", location)
    return location

def getUploadQuota():
    """
    Function returns a string containing the permitted size of files able to upload in bytes 
    """
    return config['uploadquota']

def getInfo(id,location=False):
    """
    Function returns a string containing the xml data showing the path, usedsize and quota of
    the user directory

    location: if set to false will not show the path xml data 
    """
    quota = config['quotasize']

    if location != False:
        location = locationParser(location)
        path = os.path.join(id, location)
    
    #calculate the used size
    sizePath = getUserPath(id)
    usedSize = str(getDirSize(sizePath))
        
    xmlString="<info>\n"
    if location!=False:
        xmlString+="<path><![CDATA["+location+"]]></path>\n"
    xmlString+="<usage>"+usedSize+"</usage>\n"
    xmlString+="<quota>"+quota+"</quota>\n"
    xmlString+="</info>\n"
    return xmlString
    

def dirExist(location):
    log.debug("Checking (A): " + location)
    location = locationParser(location, False)
    log.debug("Checking (B): " + location)
    requestPath = location
    return os.path.isdir(requestPath)

def showFiles(id, location):
    """
    Function returns a xml string showing of the files found at the "location" path

    id: a string containing the trefoil user's user ID

    location: a string containing the relative path to user's root directory
    """
    location = locationParser(location)
    requestPath = os.path.join(getUserPath(id), location)
    
    log.debug("Accessing to [%s]" % requestPath)
    fileList = getFilesList(requestPath)
    
    if fileList == None and dirExist(requestPath) == False:
        raise Exception("Could not access directory: " + location)

    fileList.sort()

    #generate XML 
    xmlString = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"
    xmlString += "<files>"

    #generate info section
    xmlString += getInfo(id,location)
        
    #generate XML for directories
    for item in fileList:
        if os.path.isdir(item):
            userPermission=getMode(item,"user")
            xmlString += "<dir permission=\""+userPermission+"\"><![CDATA["+os.path.basename(item)+"]]></dir>\n"
        
    #generate XML for files
    for item in fileList:
        if os.path.isfile(item):
            size=str(getFileSize(item))
            type=getMimeType(item)
            userPermission=getMode(item,"user")
            xmlString+="<file type=\""+type+"\" permission=\""+userPermission+"\" size=\""+size+"\"><![CDATA["+os.path.basename(item)+"]]></file>\n"
            
    xmlString+="</files>\n" 
    return xmlString

def delete(id,fileString):
    """
    Function deletes files or directories and returns an xml response 
    will raise an error if all operations failed

    id: a string containing the trefoil user's user ID

    fileString: a string containing the relative path to the user's root directory of the files or directories
    to delete which are seperated by a comma
    """
    #parse the file string into a list of files
    fileList=fileString.split(",")
    trueFlag=False

    #generate XML header
    xmlString="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
    xmlString+="<responses>\n"

    #generate response and delete files
    xmlFiles=""
    for item in fileList:

        #get full path and remove frontal slashes
        item=locationParser(item)
        fullPath=os.path.join(getUserPath(),id,item)
        log.debug("Deleting %s" % fullPath)
        
        if os.path.isfile(fullPath):
            fileType=getMimeType(fullPath)
            try:
                storageHelper.removeFile(fullPath)
                success="true"
                trueFlag=True
            except:
                success="false"
            xmlFiles+="<response type=\""+fileType+"\" from=\""+item+"\">"+success+"</response>\n"
        elif os.path.isdir(fullPath):
            fileType="directory"
            try:
                storageHelper.removeDir(fullPath)
                success="true"
                trueFlag=True
            except:    
                success="false"
            xmlFiles+="<response type=\""+fileType+"\" from=\""+item+"\">"+success+"</response>\n"
        else:
            fileType=getMimeType(fullPath)
            success="false"
            xmlFiles+="<response type=\""+fileType+"\" from=\""+item+"\">"+success+"</response>\n"

    #if all false return error
    if trueFlag==False:
        raise("All operations failed")
    
    #generate info section
    xmlString+=getInfo(id)

    #add reponse from files
    xmlString+=xmlFiles
    
    xmlString+="</responses>"
    return xmlString

def move(id,sourceString,destString):
    """
    Functions Moves files and directories for the user and returns an xml response
    will raise an error if all operations failed

    id: a string containing the trefoil user's user ID

    sourceString: a string containing the relative path to the user's root directory of the files or directories
    to move which are seperated by a comma

    destString: a string containing the relative path to the user's root directory of the files or directories
    move destination which are seperated by a comma
    
    """
    #parse the two strings into lists
    sourceFileList=sourceString.split(",")
    destFileList=destString.split(",")

    #generate XML header
    xmlString="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
    xmlString+="<responses>\n"

    #generate response 
    xmlFiles=""
    trueFlag=False
    
    for sourceItem,destItem in zip(sourceFileList,destFileList):

        #remove the frontal slash
        sourceItem=locationParser(sourceItem)
        destItem=locationParser(destItem)

        #add full path
        fullSourcePath=os.path.join(getUserPath(),id,sourceItem)
        fullDestPath=os.path.join(getUserPath(),id,destItem)

        #if Destination is a directory that exists add sourcename to destination path
        if os.path.isdir(fullDestPath):
            baseName=os.path.basename(fullSourcePath)
            fullDestPath=os.path.join(fullDestPath,baseName)

        if os.path.isdir(fullSourcePath):
            fileType="directory"
        else:
            fileType=getMimeType(fullSourcePath)

        #move the file   
        try:
            storageHelper.rename(fullSourcePath,fullDestPath)
            success="true"
            trueFlag=True

            #if successful rewrite fileType to new file
            
            if os.path.isdir(fullDestPath):
                fileType="directory"
            else:
                fileType=getMimeType(fullDestPath)
                
        except:
            success="false"
            
        xmlFiles+="<response type=\""+fileType+"\" from=\""+sourceItem+"\" to=\""+destItem+"\" >"+success+"</response>\n"


    #if all false return error
    if trueFlag==False:
        raise("All operations failed")

    #generate info section
    xmlString+=getInfo(id)

    #add reponse from files
    xmlString+=xmlFiles
    
    xmlString+="</responses>"
    return xmlString
